﻿using System;
using System.Collections.Generic;

namespace ParserGenerator.Extensions
{
    public static class ICollectionExtensions
    {
        private static int[] _primes =
        {
            0x00000002, 0x00000003, 0x00000005, 0x00000007,
            0x0000000b, 0x0000000d, 0x00000011, 0x00000013,
            0x00000017, 0x0000001d, 0x0000001f, 0x00000025,
            0x00000029, 0x0000002b, 0x0000002f, 0x00000035,
            0x0000003b, 0x0000003d, 0x00000043, 0x00000047,
            0x00000049, 0x0000004f, 0x00000053, 0x00000059,
            0x00000061, 0x00000067, 0x0000006d, 0x00000071,
            0x0000007f, 0x00000089, 0x0000008b, 0x00000095,
            0x0000009d, 0x000000a7, 0x000000b3, 0x000000c1,
            0x000000c7, 0x000000d3, 0x000000e3, 0x000000f1,
            0x00000101, 0x00000115, 0x00000125, 0x00000139,
            0x00000151, 0x00000167, 0x0000017f, 0x00000199,
            0x000001b7, 0x000001d3, 0x000001f7, 0x0000021d,
            0x00000241, 0x0000026b, 0x00000295, 0x000002c5,
            0x000002f9, 0x00000337, 0x00000377, 0x000003b9,
            0x00000407, 0x00000455, 0x000004a9, 0x00000509,
            0x00000565, 0x000005d5, 0x0000064d, 0x000006cd,
            0x00000757, 0x000007ed, 0x00000883, 0x00000935,
            0x000009f5, 0x00000ac1, 0x00000b9b, 0x00000c89,
            0x00000d8d, 0x00000e9b, 0x00000fbb, 0x000010fd,
            0x0000125f, 0x000013df, 0x0000157f, 0x00001741,
            0x0000191b, 0x00001b25, 0x00001d5d, 0x00001fbb,
            0x0000224f, 0x00002519, 0x00002821, 0x00002b69,
            0x00002eeb, 0x000032b7, 0x000036d1, 0x00003b45,
            0x0000401b, 0x00004555, 0x00004aef, 0x00005111,
            0x000057af, 0x00005ed9, 0x0000669b, 0x00006efb,
            0x00007807, 0x000081c7, 0x00008c5d, 0x000097d9,
            0x0000a43b, 0x0000b1a9, 0x0000c031, 0x0000cfd1,
            0x0000e0d5, 0x0000f319, 0x000106eb, 0x00011c71,
            0x000133bb, 0x00014ced, 0x0001682b, 0x00018595,
            0x0001a579, 0x0001c7fb, 0x0001ed3f, 0x0002159f,
            0x00024151, 0x0002707f, 0x0002a385, 0x0002dad3,
            0x000316a9, 0x0003575b, 0x00039d61, 0x0003e917,
            0x00043b0d, 0x000493af, 0x0004f397, 0x00055b55,
            0x0005cb8b, 0x000644e9, 0x0006c847, 0x00075671,
            0x0007f031, 0x00089699, 0x00094a87, 0x000a0d41,
            0x000adff9, 0x000bc3e9, 0x000cba85, 0x000dc553,
            0x000ee5f1, 0x00101e43, 0x00117025, 0x0012ddad,
            0x0014691d, 0x001614f1, 0x0017e3db, 0x0019d8a3,
            0x001bf671, 0x001e40a3, 0x0020bad1, 0x002368f3,
            0x00264f3d, 0x00297259, 0x002cd737, 0x00308327,
            0x00347c23, 0x0038c857, 0x003d6eaf, 0x0042767b,
            0x0047e7bd, 0x004dcb13, 0x005429d1, 0x005b0df3,
            0x006282c7, 0x006a93b5, 0x00734de3, 0x007cbf17,
            0x0086f63b, 0x00920377, 0x009df84d, 0x00aae7e9,
            0x00b8e6b9, 0x00c80adf, 0x00d86c73, 0x00ea256f,
            0x00fd51f9, 0x01121077, 0x012881db, 0x0140c9b9,
            0x015b0e8d, 0x01777a0b, 0x0196396d, 0x01b77d61,
            0x01db7a95, 0x02026a59, 0x022c8a63, 0x025a1d87,
            0x028b6c13, 0x02c0c435, 0x02fa7ab7, 0x0338eb19,
            0x037c786f, 0x03c58de1, 0x04149f67, 0x046a2a75,
            0x04c6b6eb, 0x052ad787, 0x05972b2d, 0x060c5db5,
            0x068b2929, 0x07145695, 0x07a8bfdd, 0x08495051,
            0x08f706bb, 0x09b2f6f9, 0x0a7e4b0d, 0x0b5a4593,
            0x0c4843c3, 0x0d49bf31, 0x0e60505d, 0x0f8db15b,
            0x10d3c05f, 0x123482bd, 0x13b2284d, 0x154f0e89,
            0x170dc4a5, 0x18f10f85, 0x1afbee09, 0x1d319dc9,
            0x1f95a075, 0x222bc111, 0x24f81a5d, 0x27ff1cf1,
            0x2b4596a5, 0x2ed0b9b7, 0x32a625e7, 0x36cbf04b,
            0x3b48add5, 0x40237d21, 0x45641269, 0x4b12c31f,
            0x51389375, 0x57df44d7, 0x5f1164d1, 0x66da5ead,
            0x6f468caf, 0x78634c43, 0x7feffffd, 0x7fffffff,
            0x7fffffff,
        };

        public static int GetPrime(int min)
        {
            int i = 0;
            int j = _primes.Length - 2;
            while (i <= j)
            {
                int k = i + ((j - i) >> 1);
                if (min < _primes[k])
                    j = k - 1;
                else if (min > _primes[k])
                    i = k + 1;
                else
                    return _primes[k];
            }
            return _primes[i];
        }

        public static int ItemCompareTo(object x, object y)
        {
            if (x == y)
                return 0;
            else if (x == null)
                return -1;
            else if (y == null)
                return 1;
            else
            {
                if (x is IComparable)
                    return ((IComparable)x).CompareTo(y);
                else if (y is IComparable)
                    return -((IComparable)y).CompareTo(x);
                else
                    throw new ArgumentException(SR.ObjectsAreNotComparable);
            }
        }

        public static int GetItemHashCode<T>(T obj)
        {
            return (obj != null) ? obj.GetHashCode() : 0;
        }

        public static int GetItemHashCode(object obj)
        {
            return GetItemHashCode<object>(obj);
        }

        public static int CombineHashCodes(int x, int y)
        {
            const int magicPrime = 30727;
            return x * magicPrime + y;
        }

        public static IComparer<T> AsComparer<T>(this Comparison<T> comparison)
        {
            if (comparison == null)
                throw new ArgumentNullException(nameof(comparison));
            return new FunctorComparer<T>(comparison);
        }

        [Serializable]
        private sealed class FunctorComparer<T> : IComparer<T>
        {
            private readonly Comparison<T> _comparison;

            public FunctorComparer(Comparison<T> comparison)
            {
                if (comparison == null)
                    throw new ArgumentNullException(nameof(comparison));
                _comparison = comparison;
            }

            public int Compare(T x, T y)
            {
                return _comparison(x, y);
            }
        }
    }
}
